//
// Created by JackSong on 2020/4/9.
//

#include <jni.h>
#include <cstdio>

//创建cpp默认生成的.h头文件，不需要
//#include "CppCallJava.h"

//<2-1> 非静态native方法调用CppCallJavaUtil对象中的方法
extern "C" JNIEXPORT void JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_cppCallJavaMethod(JNIEnv *env, jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/CppCallJavaUtil");
    if (clazz == NULL) {
        printf("clz is null");
        return;
    }
    // 第二个参数：java 对象的方法名
    // 第三个参数：方法签名
    jmethodID method = env->GetMethodID(clazz, "callFun", "()V");
    env->CallVoidMethod(obj, method);

    // 删除局部引用
    env->DeleteLocalRef(clazz);
}

//<2-2>  返回值int
extern "C" JNIEXPORT jint JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_cppCallJavaFunReturnInt(JNIEnv *env,
                                                                          jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/CppCallJavaUtil");
    if (clazz == NULL) {
        printf("clz is null");
        return -1;
    }
    // 第二个参数：java 对象的方法名
    // 第三个参数：方法签名
    jmethodID method = env->GetMethodID(clazz, "callFunReturnInt", "()I");
    // 使用有返回值的java方法
    return env->CallIntMethod(obj, method);
}

//<2-3>  返回值类1
extern "C" JNIEXPORT jobject JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_nativeCppCallJavaMethodReturnClass(JNIEnv *env,
                                                                                     jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/CppCallJavaUtil");
    if (clazz == NULL) {
        printf("clz is null");
        return NULL;
    }
    // 第二个参数：java 对象的方法名
    // 第三个参数：方法签名
    jmethodID method = env->GetMethodID(clazz, "callFunReturnClass",
                                        "()Lcom/sjy/jnidemo2/cppcalljava/CppCallJavaUtil;");
    // 使用有返回值的java方法
    return env->CallObjectMethod(obj, method);
}

//<2-3>  返回值类2
extern "C" JNIEXPORT jobject JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_nativeCppCallJavaMethodReturnClass2(JNIEnv *env,
                                                                                      jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/CppCallJavaUtil");
    if (clazz == NULL) {
        printf("clz is null");
        return NULL;
    }
    // 第二个参数：java 对象的方法名
    // 第三个参数：方法签名
    jmethodID method = env->GetMethodID(clazz, "callFunReturnClass2",
                                        "()Lcom/sjy/jnidemo2/cppcalljava/Person;");
    // 使用有返回值的java方法
    return env->CallObjectMethod(obj, method);

}

//<2-4>  调用静态方法
extern "C" JNIEXPORT void JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_nativeCppCallJavaStaticMethod(JNIEnv *env,
                                                                                jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/CppCallJavaUtil");
    if (clazz == NULL) {
        printf("clz is null");
        return;
    }
    // 静态方法
    jmethodID method = env->GetStaticMethodID(clazz, "callStaticFun", "()V");
    env->CallStaticVoidMethod(clazz, method);

    // 静态方法：带参数
    jmethodID method2 = env->GetStaticMethodID(clazz, "callStaticFun2", "(Ljava/lang/String;)V");
    jstring arg = env->NewStringUTF("我在c端赋值参数");
    env->CallStaticVoidMethod(clazz, method2, arg);

}

//<2-5> newObject演示,
extern "C" JNIEXPORT void JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_nativeCppCallJavaMethodOutside(JNIEnv *env,
                                                                                 jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/Person");
    if (clazz == NULL) {
        printf("clz is null");
        return;
    }

    //（1）演示Persion(int age)初始化和调用Persion.personAge()调用
    jmethodID javaMethod = env->GetMethodID(clazz, "personAge", "()V");//需要调用的Person的方法personName()
    jmethodID initClazz = env->GetMethodID(clazz, "<init>", "(I)V");
    //NewObject()
    jobject javaClazz = env->NewObject(clazz, initClazz, 29);//29为构造赋值
    //绑定调用
    env->CallVoidMethod(javaClazz, javaMethod);

    //（2）演示Persion(String name)初始化和调用Persion.personName()调用
    jmethodID javaMethod2 = env->GetMethodID(clazz, "personName", "()V");
    jmethodID initClazz2 = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;)V");//as自动生成
    jstring str_arg = env->NewStringUTF("在c端赋值的名字");
    jobject javaClazz2 = env->NewObject(clazz, initClazz2, str_arg);
    env->CallVoidMethod(javaClazz2, javaMethod2);

    //NewObject为局部引用，不释放内存
    env->DeleteLocalRef(javaClazz);
    env->DeleteLocalRef(javaClazz2);
}



//<2-6> AllocObject 演示,
extern "C" JNIEXPORT void JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_nativeCppCallJavaMethodOutside2(JNIEnv *env,
                                                                                  jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/Person");
    if (clazz == NULL) {
        printf("clz is null");
        return;
    }

    //（1）演示Persion(int age)初始化和调用Persion.personAge()调用
    jmethodID javaMethod = env->GetMethodID(clazz, "personAge", "()V");//需要调用的Person的方法personName()
    //AllocObject()
    jobject javaClazz = env->AllocObject(clazz);//
    //绑定调用
    env->CallVoidMethod(javaClazz, javaMethod);

    //（2）演示Persion(String name)初始化和调用Persion.personName()调用
    jmethodID javaMethod2 = env->GetMethodID(clazz, "personName", "()V");
    jobject javaClazz2 = env->AllocObject(clazz);//
    env->CallVoidMethod(javaClazz2, javaMethod2);

    //NewObject为局部引用，不释放内存
    env->DeleteLocalRef(javaClazz);
    env->DeleteLocalRef(javaClazz2);
}

//<2-7> 静态native调用
extern "C" JNIEXPORT void JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_staticCppCallJavaMethod(JNIEnv *env,
                                                                          jclass clazz) {
    jmethodID javaMethod = env->GetMethodID(clazz, "staticCppCallFun", "()V");
    jobject initClazz = env->AllocObject(clazz);
    env->CallVoidMethod(initClazz, javaMethod);
}

//<2-8> 访问变量,
extern "C" JNIEXPORT void JNICALL
Java_com_sjy_jnidemo2_cppcalljava_CppCallJavaUtil_cppCallJavaField(JNIEnv *env,
                                                                   jobject obj) {
    //注意：方法路径要用 ”/“ 不能使用 ”.“
//    jclass clazz = env->FindClass("com/sjy/jnidemo2/cppcalljava/CppCallJavaUtil");
//    if (clazz == NULL) {
//        printf("clz is null");
//        return;
//    }
//    // 第二个参数：java 对象的方法名
//    // 第三个参数：方法签名
//    jmethodID method = env->GetMethodID(clazz, "callFunReturnClass",
//                                        "()Lcom/sjy/jnidemo2/cppcalljava/CppCallJavaUtil;");
//    // 使用有返回值的java方法
//    env->CallObjectMethod(obj, method);

    jclass clazz2 = env->GetObjectClass(obj);
    jfieldID fieldId = env->GetFieldID(clazz2, "myAge", "I");//获取变量
    //获取变量具体类型
    jint myInt = env->GetIntField(obj, fieldId);
    //打印获取值
    printf("获取变量值: %d", myInt);

    //修改值
    env->SetIntField(obj, fieldId, myInt + 12);
    printf("修改后的值: %d", myInt);

}
